package com.ruoyi.system.service.impl;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Year;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SysClassMapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

/**
 * 排课Service业务层处理
 *
 * @author ruoyi
 * @date 2025-06-25
 */
@Service
public class SysClassServiceImpl implements ISysClassService
{
    @Autowired
    private SysClassMapper sysClassMapper;

    /** 合同service接口层 */
    @Autowired
    private ISysContractService sysContractService;

    /** 合同明细service接口层 */
    @Autowired
    private ISysContractLabelService sysContractLabelService;

    /** 数据字段service接口层 */
    @Autowired
    private ISysDictDataService sysDictDataService;

    /** 课程表明细service接口层 */
    @Autowired
    private ISysClassLabelService sysClassLabelService;

    /** 用户service接口层 */
    @Autowired
    private ISysUserService sysUserService;

    /**
     * 查询排课
     *
     * @param id 排课主键
     * @return 排课
     */
    @Override
    public SysClass selectSysClassById(Long id)
    {
        SysClass sysClass = sysClassMapper.selectSysClassById(id);
        List<SysClassLabel> sysClassLabelList = sysClassLabelService.selectSysClassLabels(sysClass.getId());
        if (!CollectionUtils.isEmpty(sysClassLabelList)){
            sysClass.setSysClassLabelList(sysClassLabelList);
        }
        return sysClass;
    }

    /**
     * 根据表头查询排课表并且上课时间要小于现在时间
     * @param classHeadId
     * @return
     */
    @Override
    public List<SysClass> selectSysClassByClassHeadIdAndClssDateBigNow(Long classHeadId,String classTimeSlot) {
        List<SysClass> sysClassList = sysClassMapper.selectSysClassByClassHeadIdAndClssDateBigNow(classHeadId,classTimeSlot);
        if (!CollectionUtils.isEmpty(sysClassList)){
            //查询更下级
            sysClassList.forEach(it -> {
                List<SysClassLabel> sysClassLabelList = sysClassLabelService.selectSysClassLabelByClassId(it.getId());
                if (!CollectionUtils.isEmpty(sysClassLabelList)){
                    it.setSysClassLabelList(sysClassLabelList);
                }
            });
        }
        return sysClassList;
    }

    /**
     * 查询排课列表
     *
     * @param sysClass 排课
     * @return 排课
     */
    @Override
    public List<SysClass> selectSysClassList(SysClass sysClass)
    {
        List<SysClass> sysClassList = sysClassMapper.selectSysClassList(sysClass);
        return sysClassList;
    }

    /**
     * 新增排课
     *
     * @param sysClass 排课
     * @return 结果
     */
    @Override
    @Transactional
    public int insertSysClass(SysClass sysClass)
    {
        int state = 0;
        try {
            //新增排课表方法
            if (null == sysClass.getId()){
                state += sysClassMapper.insertSysClass(sysClass);
            }

            //新增排课明细
            sysClass.getSysClassLabel().setClassId(sysClass.getId());
            sysClassLabelService.insertSysClassLabel(sysClass.getSysClassLabel());
        }
        catch (Exception e){
            //事务回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(e.getMessage());
        }
        return state;
    }

    /**
     * 新增课表判断方法
     * @param sysClass
     */
    @Override
    public void emptyInsertSysClass(SysClass sysClass) {
        //日期
        /*if (null == sysClass.getClassDate()){
            throw new RuntimeException("上课日期未传输，请联系管理员");
        }*/
        //时间
        //老师
        if (null == sysClass.getTeacherId()){
            throw new RuntimeException("老师信息未传，请联系管理员");
        }
    }

    /**
     * 根据合同主键创建排课表
     * @param sysClass
     * @return
     */
    @Override
    public SysClass buildClassByContractId(SysClass sysClass) {
        //创建时间
        sysClass.setCreateTime(DateUtils.getNowDate());

        //创建人
        sysClass.setCreateBy("admin");
        //sysClass.setCreateBy(SecurityUtils.getUsername());

        //状态
        sysClass.setStatus(0L);

        //课表明细
        //SysClassLabel sysClassLabel = sysClass.getSysClassLabelList().get(0);

        //查询合同明细
        SysContractLabel sysContractLabel = sysContractLabelService.selectSysContractLabelById(sysClass.getContractLabelId());
        if (null == sysContractLabel){
            throw new RuntimeException("合同明细不存在，请联系管理员");
        }

        //查询合同
        SysContract sysContract = sysContractService.selectSysContractById(sysContractLabel.getContractId());
        if (null == sysContract){
            throw new RuntimeException("合同不存在，请联系管理员");
        }

        //查询数据字典
        SysDictData sysDictData = sysDictDataService.selectDictDataById(sysContract.getContractType());

        //最大人数
        sysClass.setMaxNum(Long.parseLong(sysDictData.getDictValue()));

        //年纪
        sysClass.setGrade(sysContract.getGrade());

        //构建明细
        sysClass.setSysClassLabel(sysClassLabelService.buildSysClassLabel(sysClass));

        return sysClass;
    }

    /**
     * 修改排课
     *
     * @param sysClass 排课
     * @return 结果
     */
    @Override
    public int updateSysClass(SysClass sysClass)
    {
        sysClass.setUpdateTime(DateUtils.getNowDate());
        return sysClassMapper.updateSysClass(sysClass);
    }

    /**
     * 批量删除排课
     *
     * @param ids 需要删除的排课主键
     * @return 结果
     */
    @Override
    public int deleteSysClassByIds(Long[] ids)
    {
        return sysClassMapper.deleteSysClassByIds(ids);
    }

    /**
     * 删除排课信息
     *
     * @param id 排课主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteSysClassById(Long id)
    {
        try {
            //查询排课
            SysClass sysClass = this.selectSysClassById(id);
            if (sysClass.getStatus() == 1){
                throw new RuntimeException("当前排课已确认不可删除");
            }
            //查询排课明细
            List<SysClassLabel> sysClassLabelList = sysClassLabelService.selectSysClassLabelByClassId(id);
            sysClassLabelList.forEach(it -> {
                //查询合同明细
                SysContractLabel sysContractLabel = sysContractLabelService.selectSysContractLabelById(it.getContractLabelId());
                //剩余课时
                sysContractLabel.setRemainingClassTime(sysContractLabel.getRemainingClassTime() + 1);
                //已排未上课时
                sysContractLabel.setNotDuringClassTime(sysContractLabel.getNotDuringClassTime() - 1);
                sysContractLabelService.updateSysContractLabel(sysContractLabel);
            });
            //删除排课明细
            sysClassLabelService.deleteSysClassLabelByClassId(id);
        }
        catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(e.getMessage());
        }

        return sysClassMapper.deleteSysClassById(id);
    }

    @Override
    @DataScope(deptAlias = "sys_user",userAlias = "sys_user")
    public List<SysTeacherClass> selectTeacherClass(SysTeacherClass sysTeacherClass) {
        // 强制初始化params（解决90%的问题）
        if (sysTeacherClass.getParams() == null) {
            sysTeacherClass.setParams(new HashMap<>());
        }

        List<SysTeacherClass> teacherClassList = sysClassMapper.selectTeacherClass(sysTeacherClass);

        int currentWeekOfYear = 0;
        if (null != sysTeacherClass.getNowWeek()){
            currentWeekOfYear = sysTeacherClass.getNowWeek();
        }
        else if (null == sysTeacherClass.getNowWeek()){
            currentWeekOfYear = this.getCurrentWeekOfYear();
        }

        String[] weekRangeFormatted = this.getWeekRangeFormatted(Year.now().getValue(), currentWeekOfYear);
        sysTeacherClass.setBeginDate(weekRangeFormatted[0]);
        sysTeacherClass.setEndDate(weekRangeFormatted[weekRangeFormatted.length - 1]);

        if (!CollectionUtils.isEmpty(teacherClassList)){
            //查询课程
            teacherClassList.forEach(it -> {
                List<SysClassView> sysClassViewList = new ArrayList<>();
                //查询上课时间
                List<String> sysDictData = sysDictDataService.selectDictLabelByDictType("class_time_slot");
                for (int i = 0; i < weekRangeFormatted.length; i++) {
                    for (int i1 = 0; i1 < sysDictData.size(); i1++) {
                        SysClassView sysClassView = new SysClassView();
                        sysClassView.setClassTimeSlot(sysDictData.get(i1));
                        sysClassView.setBeginDate(weekRangeFormatted[i]);
                        sysClassView.setEndDate(weekRangeFormatted[weekRangeFormatted.length - 1]);
                        //老师名称
                        if (!StringUtils.isEmpty(it.getTeacherName())){
                            sysClassView.setTeacherName(it.getTeacherName());
                        }
                        //查询课程
                        SysClass sysClass = sysClassMapper.selectSysClassByTeacherIdAndDateAndClassDateAndClassTimeSlot(sysClassView);
                        if (null != sysClass){
                            sysClassView.setSysClass(sysClass);
                        }
                        sysClassViewList.add((sysClassView));
                    }
                }
                // 按 classTimeSlot 排序（提取 "08:00" 部分进行比较）
                sysClassViewList.sort(Comparator.comparing(
                        view -> view.getClassTimeSlot().split("-")[0].trim(), // 提取开始时间（如 "08:00"）
                        Comparator.naturalOrder() // 升序排序
                ));

                // 2. 按相同的 classTimeSlot 分组
                Map<String, List<SysClassView>> groupedByTimeSlot = sysClassViewList.stream()
                        .collect(Collectors.groupingBy(SysClassView::getClassTimeSlot));

                // 3. 将分组结果转换为 List<List<SysClassView>>
                List<List<SysClassView>> sysClassViewssList = new ArrayList<>(groupedByTimeSlot.values());
                sysClassViewssList.sort(Comparator.comparing(
                        list -> list.get(0).getClassTimeSlot().split("-")[0].trim()
                ));

                List<SysClassViews> sysClassViewsList = new ArrayList<>();
                for (int i = 0;i < sysClassViewssList.size();i++){
                    List<SysClassView> sysClassViewList1 = sysClassViewssList.get(i);
                    SysClassViews sysClassViews = new SysClassViews();
                    sysClassViews.setClassTimeSlot(sysClassViewList1.get(0).getClassTimeSlot());
                    sysClassViews.setSysClassViewList(sysClassViewList1);
                    sysClassViewsList.add(sysClassViews);
                }

                it.setSysClassViewsList(sysClassViewsList);
            });
        }
        return teacherClassList;
    }

    /**
     * 获取当前日期是今年的第几周（ISO标准周）
     */
    public int getCurrentWeekOfYear() {
        LocalDate today = LocalDate.now();
        return today.get(WeekFields.of(Locale.getDefault()).weekOfWeekBasedYear());
    }

    public LocalDate[] getWeekRange(int year, int week) {
        // 使用 ISO 标准（周一为第一天）
        WeekFields weekFields = WeekFields.ISO;

        // 计算该年的第 1 周的第 1 天（周一）
        LocalDate firstDayOfYear = LocalDate.of(year, 1, 1)
                .with(weekFields.dayOfWeek(), 1);

        // 计算目标周的周一
        LocalDate firstDayOfWeek = firstDayOfYear.plusWeeks(week - 1);

        // 创建包含7天的数组（周一到周日）
        LocalDate[] weekDays = new LocalDate[7];

        // 填充周一到周日的日期
        for (int i = 0; i < 7; i++) {
            weekDays[i] = firstDayOfWeek.plusDays(i);
        }

        return weekDays;
    }

    @Override
    public String[] getWeekRangeFormatted(int year, int week) {
        DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate[] weekRange = getWeekRange(year, week);
        return Arrays.stream(weekRange)
                .map(date -> date.format(DATE_FORMATTER))
                .toArray(String[] :: new);
    }

    /**
     * 确认排课
     * @param sysClass
     * @return
     */
    @Override
    @Transactional
    public int confirmClass(SysClass sysClass) {
        int count = 0;
        try {
            //查询课时
            SysClass querySysClass = this.selectSysClassById(sysClass.getId());
            if (null == querySysClass){
                throw new RuntimeException("未查询到课时信息，请联系管理员");
            }
            //确认时间
            querySysClass.setConfirmDate(DateUtils.getNowDate());
            //确认者
            SysUser sysUser = sysUserService.selectUserById(SecurityUtils.getUserId());
            querySysClass.setConfirmper(sysUser.getNickName());

            //查询课程之下的明细
            List<SysClassLabel> sysClassLabelList = sysClassLabelService.selectSysClassLabelByClassId(querySysClass.getId());
            for (int i = 0; i < sysClassLabelList.size(); i++) {
                SysClassLabel sysClassLabel = sysClassLabelList.get(i);
                //查询对应的课时
                SysContractLabel sysContractLabel = sysContractLabelService.selectSysContractLabelById(sysClassLabel.getContractLabelId());
                if (sysContractLabel.getNotDuringClassTime() != 0){
                    sysContractLabel.setNotDuringClassTime(sysContractLabel.getNotDuringClassTime() - 1);
                    //已上课时
                    sysContractLabel.setDuringClassTime(sysContractLabel.getDuringClassTime() + 1);
                    //如果合同明细剩余课时与已排未上课时都为0则查询其合同下的所有课程剩余课时与已排未上课时是否都为0
                    if (sysContractLabel.getNotDuringClassTime() == 0 && sysContractLabel.getRemainingClassTime() == 0){
                        SysContract sysContract = sysContractService.selectSysContractById(sysContractLabel.getContractId());
                        //查询其下所有明细并且不是当前明细
                        List<SysContractLabel> sysContractLabelList = sysContractLabelService.selectSysContractLabelByContractId(sysContract.getId());
                        boolean flag = false;
                        for (int i1 = 0; i1 < sysContractLabelList.size(); i1++) {
                            SysContractLabel sysContractLabel1 = sysContractLabelList.get(i1);
                            if (!sysContractLabel1.getId().equals(sysContractLabel.getId())){
                                //剩余课时大于0
                                if (sysContractLabel1.getRemainingClassTime() > 0){
                                    flag = true;
                                }
                                //排课未上课时
                                if (sysContractLabel1.getNotDuringClassTime() > 0){
                                    flag = true;
                                }
                            }
                        }
                        //如果剩余课时与排课未上课时都为0则合同为已完结
                        if (!flag){
                            sysContract.setStatus(1L);
                            sysContractService.updateSysContract(sysContract);
                        }
                    }
                    //修改合同明细已排未上课时
                    count = sysContractLabelService.updateSysContractLabel(sysContractLabel);
                }
            }
            querySysClass.setStatus(1L);
            count = this.updateSysClass(querySysClass);
        }
        catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(e.getMessage());
        }
        return count;
    }

    /**
     * 确认课时列表
     * @param sysClass
     * @return
     */
    @Override
    public List<SysClass> confirmList(SysClass sysClass) {
        return sysClassMapper.confirmList(sysClass);
    }

    /**
     * 老师请假
     * @param sysClass
     * @return
     */
    @Override
    @Transactional
    public int askForLeave(SysClass sysClass) {
        int count = 0;
        try {
            //查询
            SysClass querySysClass = this.selectSysClassById(sysClass.getId());
            //查询明细
            List<SysClassLabel> sysClassLabelList = sysClassLabelService.selectSysClassLabelByClassId(sysClass.getId());
            sysClassLabelList.forEach(it -> {
                //查询合同明细
                SysContractLabel sysContractLabel = sysContractLabelService.selectSysContractLabelById(it.getContractLabelId());
                //剩余时间
                sysContractLabel.setRemainingClassTime(sysContractLabel.getRemainingClassTime() + 1);
                //已排未上课时
                sysContractLabel.setNotDuringClassTime(sysContractLabel.getNotDuringClassTime() - 1);
                sysContractLabelService.updateSysContractLabel(sysContractLabel);
            });
            querySysClass.setStatus(3L);
            count = this.updateSysClass(querySysClass);
        }
        catch (Exception e){
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new RuntimeException(e.getMessage());
        }
        return count;
    }
}